#ifdef _PLATFORM_WII
#include "wii_audio.h"
#include "audio_set.h"


#include "script/scripthelper.h"
#include "bass/bass.h"
#include "vfs/vfs.h"
#include "font/font_manager.h"
#include "dd/dd_man.h"

#include "util/file_io.h"				// log
#include "util/timer.h"				// log
#include "util/log.h"				// log
#include "util/common_macros.h"		// macros
#include "util/mmgr.h"	 
#include <revolution.h>
#include <revolution/os.h>
#include <revolution/mix.h>
extern "C"
{
	#include "stb_vorbis.c"				// OGG Vorbis decoder
}

using namespace audio;


static AXPBMIX g_mix = {
    0x8000,       // volume left 
    0x0000,       // volume ramp left
    0x8000,       // volume right
    0x0000,       // volume ramp right
    
    0x0000,       // volume AUX A left
    0x0000,       // volume ramp AUX A left
    0x0000,       // volume AUX A right
    0x0000,       // volume ramp AUX A right
    
    0x0000,       // volume AUX B left
    0x0000,       // volume ramp AUX B left
    0x0000,       // volume AUX B right
    0x0000,       // volume ramp AUX B right
    
    0x0000,       // volume AUX C left
    0x0000,       // volume ramp AUX C left
    0x0000,       // volume AUX C right
    0x0000,       // volume ramp AUX C right
    
    0x0000,       // volume surround
    0x0000,       // volume ramp surround
    0x0000,       // volume AUX A surround
    0x0000,       // volume ramp AUX A surround
    0x0000,       // volume AUX B surround
    0x0000,       // volume ramp AUX B surround
    0x0000,       // volume AUX C surround
    0x0000,       // volume ramp AUX C surround
};

static AXPBVE g_ve = {
    0x8000,     // volume at start of frame, 0x8000 = 1.0
    0           // signed per sample delta (160 samples per frame)
};

// Voice  Defines
#define VOICE_PRIO_HIGH 31
#define VOICE_PRIO_MED  15
#define VOICE_PRIO_LOW  1

#define VOICE_STATE_STOPPED        0
#define VOICE_STATE_START          1
#define VOICE_STATE_STARTED        2
#define VOICE_STATE_PLAYING        3
#define VOICE_STATE_STOP           4


void WiiAudio::AudioFrameCallback(void)
{
	float	TimeStamp = TIMER().GetTimeStamp();
	u32 i;
    BOOL bStopFlag = FALSE;

	 WiiAudio&	This = Instance();
	 
    // Monitor each voice and process states. This must be done in the
    // callback
    for (i = 0; i < AX_MAX_VOICES; i++)
    {

        // Skip NULL entries
        AXVPB*	pVoice = This.m_VoiceA[i].pVoice;
        if (!pVoice ) continue;	// invalid

        switch (This.m_VoiceA[i].State)
        {
            case VOICE_STATE_STOPPED:
                break;
            case VOICE_STATE_START:
                // Start the voice
                AXSetVoiceState(pVoice, AX_PB_STATE_RUN);
                This.m_VoiceA[i].State = VOICE_STATE_STARTED;
                break;
            case VOICE_STATE_STARTED:
                // Skip a frame
                This.m_VoiceA[i].State = VOICE_STATE_PLAYING;
                break;
            case VOICE_STATE_PLAYING:
                // Check to see if the voice is finished, if so, stop it
				if (This.m_VoiceA[i].pStream)
				{
					OggStream* pStream = This.m_VoiceA[i].pStream;			
		            unsigned int NewStreamPos = (u32)(pVoice->pb.addr.currentAddressHi << 16) | (pVoice->pb.addr.currentAddressLo);
	            	NewStreamPos*=2;	// because we're dealing with 16 bit samples

					// visualize the flow along the buffer
					/*
					dd::Manager& DD = dd::Manager::Instance();
					// draw the line
					math::Vec2 From(0.0f, 0.8f);
					math::Vec2 To(1.0f, 0.8f);
					DD.AddLine2D(From, To, ColorRGBA(255, 255, 255));

					
					float	t = float(NewStreamPos - (OSCachedToPhysical(pStream->MusicBufferA)))/ float(OggStream::MUSIC_BUFFER*2);
					math::Vec2 Current = From + ((To-From)*t);
					math::Vec2 Offset(0, 0.1f);
					DD.AddLine2D(Current-Offset, Current+Offset, ColorRGBA(255, 255, 255));					

	            	*/
	            	// did we just loop over?
		            if (NewStreamPos < pStream->MusicBufferPos)
		            {
		            	// need to fill the 2nd half buffer
		            	bool 	Success = This.ProcessStream(STREAM_SECOND_HALF, pStream, pVoice);
		            	if (!Success)
		            	{
		            		// shutdown stream
		            		bStopFlag = true;
		            		This.ShutdownStream(pStream);
		            	}
		            }
		            else
		           	// did we just pass the halfway mark?
		           	if (pStream->MusicBufferPos < pStream->MusicBufferHalf &&
		           		NewStreamPos >= pStream->MusicBufferHalf)
		           	{
		            	bool 	Success = This.ProcessStream(STREAM_FIRST_HALF, pStream, pVoice);	           	
		            	if (!Success)
		            	{
		            		// shutdown stream
		            		bStopFlag = true;
		            		This.ShutdownStream(pStream);
		            	}
		           	}
		            pStream->MusicBufferPos = NewStreamPos;
		            
              	} 
	            if (This.m_VoiceA[i].pVoice->pb.state == AX_PB_STATE_STOP)
	           	{
	           		if (This.m_VoiceA[i].pStream)
	           		{
	           			int j=0;
	           		}
					This.m_VoiceA[i].State = VOICE_STATE_STOP;
				}              	 
                break;
            case VOICE_STATE_STOP:
                // Force a voice to stop
                bStopFlag = TRUE;
                break;
        }

        // A voice must be stopped
        if (bStopFlag)
        {
        	This.StopSound(i);
            bStopFlag = FALSE;
        }
    }
	/*float	ToTimeStamp = TIMER().GetTimeStamp();
	float	TimeCutoff = 0.003;
		if (ToTimeStamp - TimeStamp > TimeCutoff)
	{
		FontManager::Instance().PrintCentered(math::Vec2(0.5f, 0.6f), "Synching audio stream");
	
	}*/
}

void WiiAudio::VoiceCallback(void * voiceIn)
{
    AXVPB *voice = (AXVPB*)voiceIn;

    // Note: Voice is auto-magically stopped by AX layer when dropped
	 WiiAudio&	This = Instance();

    // Application clean-up
    This.m_VoiceA[voice->index].pVoice = NULL;
    This.m_VoiceA[voice->index].State = VOICE_STATE_STOPPED;
}


static	void TimeExceeded(unsigned long Ticks)
{
	int j=0;
//	FontManager::Instance().PrintCentered(math::Vec2(0.5f, 0.6f), "Time ExceededN %i", Ticks);
}

WiiAudio&	WiiAudio::Instance()
{
	static WiiAudio Inst;
	return Inst;
}


void		WiiAudio::Init(const std::string& AudioSetFile)
{
	m_IsInit = false;
    // initialize AI & AX
    MMGR_Free(m_pBuffer);
    m_pBuffer = MMGR_AllocEx(HEAP_MEM1, AXGetMemorySize(AX_MAX_VOICES), 32);
    char* mixBuffer = (char*)MMGR_AllocEx(HEAP_MEM1, MIXGetMemorySize(AX_MAX_VOICES), 32);

    
    AIInit(NULL);
    AXInitSpecifyMem(AX_MAX_VOICES, m_pBuffer);
	AXRegisterCallback(&AudioFrameCallback);
    MIXInitSpecifyMem(mixBuffer);
	AXRegisterExceedCallback(TimeExceeded);
	
	
	
	Audio::Init(AudioSetFile);
}

void		WiiAudio::Shutdown()
{
	if (m_IsInit)
	{
		// do any deinit here?
	
	    MMGR_Free(m_pBuffer);
		m_IsInit = false;
	}
}


unsigned int	WiiAudio::GetFileSize(AudioHandle	Handle)
{
	Sample*	pSample = m_Samples.GetElement(Handle);
	if (pSample && pSample->pData)
	{
		return pSample->Size;
	}
	return 0;
}
AudioHandle	WiiAudio::PlaySFX(AudioFile	ID , float AudioBias)
{
	if (!m_IsInit) return 0;
	if (m_SFXVolume <= 0) return 0;

	Sample*	pSample = m_Samples.GetElement(ID);
	if (pSample && pSample->pData)
	{
		AudioHandle Channel = 0;
		
	    // Allocate a voice for use
	    AXVPB*   pVoice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);
    	AXPBADDR            addr;
		AXPBSRC             src;
    	AXPBADPCMLOOP       adpcmLoop; 
    	AXPBADPCM           adpcm;
	
	    
	    if (!pVoice)
	    {
	    	_LOG(MSG_ERROR, "Unable to play audio file.. cannot allocate voice!");
	    	return 0;
	    }
	    
	    
	    if (m_VoiceA[pVoice->index].pVoice)
	    {
	    	int j=0;
	    }
	    

	    addr.loopFlag = AXPBADDR_LOOP_OFF;
	    addr.format = AX_PB_FORMAT_PCM16;	 

		unsigned int 	pMRAMStart = OSCachedToPhysical(pSample->pData); 
	    unsigned int	mramAddress   = pMRAMStart / 2;
	    addr.loopAddressHi      = (u16)(mramAddress >> 16);
	    addr.loopAddressLo      = (u16)(mramAddress & 0xFFFF);

	    addr.currentAddressHi   = (u16)(mramAddress >> 16);
	    addr.currentAddressLo   = (u16)(mramAddress & 0xFFFF);	 	    

	    mramAddress             = (pSample->Size + pMRAMStart) /2;
	    addr.endAddressHi       = (u16)(mramAddress >> 16);
	    addr.endAddressLo       = (u16)(mramAddress & 0xFFFF);

 
    // Fill AXPBADPCM structure
	    adpcm.a[0][0]           = 0;
	    adpcm.a[0][1]           = 0;
	    adpcm.a[1][0]           = 0;
	    adpcm.a[1][1]           = 0;
	    adpcm.a[2][0]           = 0;
	    adpcm.a[2][1]           = 0;
	    adpcm.a[3][0]           = 0;
	    adpcm.a[3][1]           = 0;
	    adpcm.a[4][0]           = 0;
	    adpcm.a[4][1]           = 0;
	    adpcm.a[5][0]           = 0;
	    adpcm.a[5][1]           = 0;
	    adpcm.a[6][0]           = 0;
	    adpcm.a[6][1]           = 0;
	    adpcm.a[7][0]           = 0;
	    adpcm.a[7][1]           = 0;
	    adpcm.gain              = 0x0800;
	    adpcm.pred_scale        = 0;
	    adpcm.yn1               = 0;
	    adpcm.yn2               = 0; 


		// Fill AXPBSRC structure for proper sample rates
		unsigned int	srcBits = (u32)(0x00010000 * ((f32)pSample->SampleRate / AX_IN_SAMPLES_PER_SEC));
		src.ratioHi = (u16)(srcBits >> 16);
		src.ratioLo = (u16)(srcBits & 0xFFFF);
		src.currentAddressFrac = 0;
		src.last_samples[0] = 0;
		src.last_samples[1] = 0;
		src.last_samples[2] = 0;
		src.last_samples[3] = 0;

		// Set voice type
		AXSetVoiceType(pVoice, AX_PB_TYPE_NORMAL);

		// Set Address and ADPCM information from header
		AXSetVoiceAddr(pVoice, &addr);
		AXSetVoiceAdpcm(pVoice, &adpcm);
		AXSetVoiceAdpcmLoop(pVoice, &adpcmLoop);

		// Set simple volumes
		AXSetVoiceMix(pVoice, &g_mix);
		AXSetVoiceVe(pVoice, &g_ve);

		// Set sample rate
		AXSetVoiceSrcType(pVoice, AX_SRC_TYPE_LINEAR);
		AXSetVoiceSrc(pVoice, &src); 

	    m_VoiceA[pVoice->index].pVoice = pVoice;
	    m_VoiceA[pVoice->index].State = VOICE_STATE_START;
	    m_VoiceA[pVoice->index].pStream = NULL;	// only when playing from stream

		return pVoice->index;
	}
	return 0;
}


AudioFile	WiiAudio::LoadSoundFromMemory(vfs::LoadedBlock& Data, bool Repeat)
{
	unsigned int Flags = 0;
	int		Error = 0;

	// number of data-channels
	int offset = 0; 
	int	data_len = 0;

// open file
	const char*	Filename = Data.FileName.c_str();
	stb_vorbis *v = stb_vorbis_open_memory(Data.DataArray, Data.Size, &Error, NULL);
	if (!v)
	{
		_LOG(MSG_ERROR, "Unable to parse Vorbis file " << Data.FileName);
		return NULL;
	}
	int		Channels = v->channels;
	int 	total = OSRoundUp32B(stb_vorbis_stream_length_in_samples(v)); 	// does this always guarantee length?
	float	Length =  stb_vorbis_stream_length_in_seconds(v);
	// allocate space for it
	short*	data = (short *) MMGR_AllocEx(HEAP_MEM1, (total * sizeof(short)), 32);
	if (data == NULL) 
	{
		stb_vorbis_close(v);
		_LOG(MSG_ERROR, "Unable to allocate " << total * sizeof(short) << " bytes for Vorbis file " << Data.FileName);
		return NULL;
	}
	// iterate through
	int	RequestedChannels = 1;
	for (;;) 
	{
		// we're only interested in single channel here!
		int n = stb_vorbis_get_frame_short_interleaved(v, RequestedChannels, data+offset, total-offset);	
		if (n == 0) break;	// done!
		if (n < 0) break;
		
		if (total - offset < 0) 
		{
			assert(!"Invalid data-length!");
		}

		
		data_len += n;
		offset += n * RequestedChannels;
	}
	stb_vorbis_close(v);

	
	Sample*	pSample = new Sample;
	pSample->SampleRate = v->sample_rate;
	pSample->File = Data.FileName;
	pSample->Handle = m_Samples.GetKey(Data.FileName);
	pSample->pData = (void*)data;
	pSample->Size = total*sizeof(short);	// size is in bytes, not in samples
	m_Samples.AddElement(Data.FileName, pSample);
	DCFlushRangeNoSync(pSample->pData, pSample->Size);
	
	return pSample->Handle;
}

bool		WiiAudio::IsPlaying(AudioHandle Handle)
{
	if (!m_IsInit) return false;
	if (Handle==0) return false;
	
	return false;
	// check against voice data here?
	
	//return BASS_ChannelIsActive(Handle) == BASS_ACTIVE_PLAYING;
}

void		WiiAudio::StopSound(AudioHandle Handle)
{
	if (!m_IsInit) return;
	if (Handle >=0 && Handle < AX_MAX_VOICES)
	{
	    AXSetVoiceState(m_VoiceA[Handle].pVoice, AX_PB_STATE_STOP);
	    AXFreeVoice(m_VoiceA[Handle].pVoice);
	    m_VoiceA[Handle].pVoice = NULL;
	    m_VoiceA[Handle].pStream = NULL;
	    m_VoiceA[Handle].State = VOICE_STATE_STOPPED;
	}
}

void		WiiAudio::StopMusic()
{
	if (!m_IsInit) return;
	if (m_pMusic && m_pMusic->VoiceID >=0)
	{
		StopSound(m_pMusic->VoiceID);
		m_pMusic->VoiceID = -1;	// invalid
	}
}


void		WiiAudio::PauseAll()
{
	if (!m_IsInit) return;

//	BASS_Pause();
}

void		WiiAudio::RestartAll()
{
	if (!m_IsInit) return;

//	BASS_Start();
}

void		WiiAudio::SetMusicVolume(int	Volume)
{
	Audio::SetMusicVolume(Volume);
	if (m_CurrentMusic)
	{	
//		BASS_ChannelSetAttributes(m_CurrentMusic, -1,(int)( m_MusicVolume * m_MusicBias), -101);
	}
}

AudioHandle		WiiAudio::PlayMusicH(AudioFile Handle, float AudioBias )
{
	if (!m_IsInit) return 0;

	return 0;

}



void		WiiAudio::ShutdownStream(OggStream* pStream)
{
	if (pStream->pStream)
		stb_vorbis_close(pStream->pStream);
	
	// is there a gentler way to do this?
	OSCancelThread(&pStream->Worker);
	
	// do we clear the raw buffer, or just reuse that as well?
	UTIL_SAFE_DELETEA(pStream->RawBufferA);
	
//	UTIL_SAFE_DELETE(pStream);		// don't delete it, just reuse it.

}


void	WiiAudio::OggStream::WaitForWorker()
{
// do we need a mutex here?
	while (DecodeStatus == DECODE_PROCESSING)
		VIWaitForRetrace();	// sleep a bit 
}


void*	WiiAudio::OggStream::WorkerThreadFn(void* pData)
{
	OggStream* pThis = (OggStream*)pData;

	/// uncompress
	int	RequestedChannels = 1;
	int	Available, Offset;
	do
	{	
		pThis->DecodeStatus = DECODE_PROCESSING;
		Available = sizeof(pThis->WorkerBufferA);
		Offset = 0;
		for (;;) 
		{
			// we're only interested in single channel here!
			// the stream is tracking automatically, and advancing as it goes
			int n = stb_vorbis_get_frame_short_interleaved(pThis->pStream, RequestedChannels, &pThis->WorkerBufferA[Offset], Available/sizeof(short));	

			if (n == 0) 
				break;	// done
				
			if (n < 0) 
			{
				pThis->DecodeStatus = DECODE_ERROR;	// oooopsi
				return NULL;
			}
			
			Available -= (n * RequestedChannels) * sizeof(short);
			Offset += n * RequestedChannels;
			// are we about to run out of space?
			
			if (Available ==0) 	// temp buffer's empty
				break;
		}
		if (Offset==0)	// nothing loaded... end of stream probably
		{
			if (pThis->Repeat)
			{
   				stb_vorbis_seek_start(pThis->pStream);
			}
			else
			{
				pThis->DecodeStatus = DECODE_STREAM_END;
				return NULL;
			}
		}
		else
		{
			pThis->DecodeStatus = DECODE_PROCESSING_COMPLETE;
		}
		
		if (pThis->DecodeStatus == DECODE_PROCESSING_COMPLETE)
		{
			// spin until the master's fetched his data
			//DCFlushRangeNoSync(pThis->WorkerBufferA, sizeof(pThis->WorkerBufferA));
			OSSuspendThread(&pThis->Worker);
		}	// otherwise load the next frame again
		
	} while (pThis->DecodeStatus != DECODE_ERROR);
	return NULL;
}

// returns false if stream is over
bool		WiiAudio::ProcessStream(WiiAudio::STREAM_OPTIONS Option, OggStream* pStream, AXVPB* pVoice)
{	

/*	// since the buffer's NULLed out at start
	// you can use this to test if the stack's creeping into the bottom of the stream
	for (unsigned int i=0; i<OggStream::MUSIC_BUFFER; i++)
	{
		if (pStream->MusicBufferA[i] != 0)
		{
			int j=0;
		}
	}
	return true;*/

	int	Offset = 0;
	if (Option == STREAM_SECOND_HALF)
		Offset = OggStream::MUSIC_BUFFER/2;
	
	int	Total = (OggStream::MUSIC_BUFFER/2) * sizeof(short);
	
	// do we need a semaphor around this?	
	if (pStream->DecodeStatus > DECODE_PROCESSING_COMPLETE )	// error of some kind
		return false;	// how to handle that?
	
	// do we allow ourselves to spin here?
	if (pStream->DecodeStatus == DECODE_PROCESSING)				// not 
	{
		memset(&pStream->MusicBufferA[Offset], 0, Total);
	}
	else
	{
		// copy across
		memcpy(&pStream->MusicBufferA[Offset], &pStream->WorkerBufferA[0], Total); 
		pStream->DecodeStatus = DECODE_PROCESSING;	// signal to thread it's good to go again!
		OSResumeThread(&pStream->Worker);	// get back to work!
	}
	
	
	DCFlushRangeNoSync(&pStream->MusicBufferA[Offset], Total);

	//	if we just filled the first chunk, also need to setup the buffer
	if (Option == STREAM_FIRST_HALF)
	{

	    AXPBADPCMLOOP   loop;        
	    loop.loop_pred_scale    = (u16)(*((u8*)(pStream->MusicBufferA)));
	    loop.loop_yn1           = 0;
	    loop.loop_yn2           = 0;

	    AXSetVoiceAdpcmLoop(pVoice, &loop);
	}


	return true;
}

	
AudioHandle	WiiAudio::PlayMusic(const std::string& Name, float AudioBias, bool Repeat)
{
	return 0;
	if (!m_IsInit) return 0;
	return 0;

	bool	ShouldStop = false;
	if (Name==m_MusicFile) return m_CurrentMusic;	// off you go

	m_MusicFile = Name;
	
	// clear whatever was happening before
	if (m_pMusic)	// stop music if playing
	{
		ShutdownStream(m_pMusic);
		StopMusic();
	}
	else
	{
		// need to do a first init of this sound-file
		m_pMusic = (OggStream*)MMGR_AllocEx(HEAP_MEM1, sizeof(OggStream), 32);
		memset(m_pMusic, 0, sizeof(OggStream));
	}
	

	// load the file
	util::FileIO File;
	if (!File.Open(Name, 
		util::AbstractFile::FILE_READ| 
		util::AbstractFile::FILE_BINARY|  
		util::AbstractFile::FILE_DISC)) 
	{
		_LOG(MSG_ERROR, "Unable to load music file " << Name);
		ShutdownStream(m_pMusic);
		return false;
	}
	
	// load the raw ogg data
	m_pMusic->RawBufferSize = File.GetSize();
	m_pMusic->RawBufferA = (unsigned char*)MMGR_AllocEx(HEAP_MEM2, m_pMusic->RawBufferSize, 32);
	if (!File.Read(m_pMusic->RawBufferA, m_pMusic->RawBufferSize))
	{
		_LOG(MSG_ERROR, "Unable to load music file " << Name);
		ShutdownStream(m_pMusic);
		return false;
	}	

	// open the Vorbis stream. 
	int	Error;
	m_pMusic->pStream = stb_vorbis_open_memory(m_pMusic->RawBufferA, m_pMusic->RawBufferSize, &Error, NULL);
	if (!m_pMusic->pStream)
	{
		_LOG(MSG_ERROR, "Unable to parse Vorbis file " << Name);
		ShutdownStream(m_pMusic);
		return false;
	}
	
	// setup our worker thread
	bool Result = OSCreateThread(
			&m_pMusic->Worker, 
			m_pMusic->WorkerThreadFn, m_pMusic, 	// action and paramenter
			(void*)(&m_pMusic->DecodeStackA[OggStream::WORKER_STACK_SIZE]), 	// stack grows downwards
			OggStream::WORKER_STACK_SIZE, // custom stack. Yay for low-level coding
			18,	// low priority = 31.
			0);	// flags. Ignore for now.
	if (Result)
	{
		OSResumeThread(&m_pMusic->Worker);
	}

	m_pMusic->Channels = m_pMusic->pStream->channels;
	m_pMusic->SampleRate = m_pMusic->pStream->sample_rate;
	m_pMusic->Samples = stb_vorbis_stream_length_in_samples(m_pMusic->pStream ); 	//each samples's a short length
	m_pMusic->Repeat = Repeat;
	
	// create the voice

	AudioHandle Channel = 0;
	
    // Allocate a voice for use
    AXVPB*   pVoice = AXAcquireVoice(VOICE_PRIO_MED, VoiceCallback, 0);

    
    if (!pVoice)
    {
    	_LOG(MSG_ERROR, "Unable to play audio file.. cannot allocate voice!");
		ShutdownStream(m_pMusic);
    	return 0;
    }
	m_pMusic->VoiceID = pVoice->index;    
    
	// decompress a chunk
	m_pMusic->WaitForWorker();	
	ProcessStream(STREAM_FIRST, m_pMusic, pVoice);
	m_pMusic->WaitForWorker();
	ProcessStream(STREAM_SECOND_HALF, m_pMusic, pVoice);


	AXPBADDR            addr;
	AXPBSRC             src;
	AXPBADPCMLOOP       adpcmLoop; 
	AXPBADPCM           adpcm;

    addr.loopFlag 			= AXPBADDR_LOOP_ON;
    addr.format 			= AX_PB_FORMAT_PCM16;	 
	unsigned int pMRAMStart = OSCachedToPhysical(m_pMusic->MusicBufferA); 
 
    MIXInitChannel(pVoice, 0, 0, -904, -904, -904, 0, 127, 0);


    m_pMusic->MusicBufferHalf 	= OSCachedToPhysical(&m_pMusic->MusicBufferA[(OggStream::MUSIC_BUFFER/2)]);
    m_pMusic->MusicBufferEnd	= OSCachedToPhysical(&m_pMusic->MusicBufferA[OggStream::MUSIC_BUFFER-1]);
    m_pMusic->MusicBufferPos 	= OSCachedToPhysical(&m_pMusic->MusicBufferA[0]);

    unsigned int mramAddress = m_pMusic->MusicBufferPos / 2;
    addr.loopAddressHi      = (u16)(mramAddress >> 16);
    addr.loopAddressLo      = (u16)(mramAddress & 0xFFFF);

    addr.currentAddressHi   = (u16)(mramAddress >> 16);
    addr.currentAddressLo   = (u16)(mramAddress & 0xFFFF);	 	    

    mramAddress             = (	m_pMusic->MusicBufferEnd ) /2;
    addr.endAddressHi       = (u16)(mramAddress >> 16);
    addr.endAddressLo       = (u16)(mramAddress & 0xFFFF);


// Fill AXPBADPCM structure
    adpcm.a[0][0]           = 0;
    adpcm.a[0][1]           = 0;
    adpcm.a[1][0]           = 0;
    adpcm.a[1][1]           = 0;
    adpcm.a[2][0]           = 0;
    adpcm.a[2][1]           = 0;
    adpcm.a[3][0]           = 0;
    adpcm.a[3][1]           = 0;
    adpcm.a[4][0]           = 0;
    adpcm.a[4][1]           = 0;
    adpcm.a[5][0]           = 0;
    adpcm.a[5][1]           = 0;
    adpcm.a[6][0]           = 0;
    adpcm.a[6][1]           = 0;
    adpcm.a[7][0]           = 0;
    adpcm.a[7][1]           = 0;
    adpcm.gain              = 0x0800;
    adpcm.pred_scale        = 0;
    adpcm.yn1               = 0;
    adpcm.yn2               = 0; 


	// Fill AXPBSRC structure for proper sample rates
	unsigned int	srcBits = (u32)(0x00010000 * ((f32)m_pMusic->SampleRate / AX_IN_SAMPLES_PER_SEC));
	src.ratioHi = (u16)(srcBits >> 16);
	src.ratioLo = (u16)(srcBits & 0xFFFF);
	src.currentAddressFrac = 0;
	src.last_samples[0] = 0;
	src.last_samples[1] = 0;
	src.last_samples[2] = 0;
	src.last_samples[3] = 0;

	// Set voice type
	AXSetVoiceType(pVoice, AX_PB_TYPE_NORMAL);

	// Set Address and ADPCM information from header
	AXSetVoiceAdpcm(pVoice, &adpcm);
	AXSetVoiceAdpcmLoop(pVoice, &adpcmLoop);

	// Set simple volumes
	AXSetVoiceMix(pVoice, &g_mix);
	AXSetVoiceVe(pVoice, &g_ve);

	// Set sample rate
	AXSetVoiceSrcType(pVoice, AX_PB_TYPE_STREAM);
    AXSetVoiceState  (pVoice, AX_PB_STATE_RUN);
	AXSetVoiceSrc(pVoice, &src); 
	AXSetVoiceAddr(pVoice, &addr);
	
    m_VoiceA[pVoice->index].pVoice = pVoice;
    m_VoiceA[pVoice->index].State = VOICE_STATE_START;
    m_VoiceA[pVoice->index].pStream = m_pMusic;

	return pVoice->index;
}
#endif
